from enum import auto, Enum

class TokenType(Enum):
    """C99令牌类型枚举"""
    # 关键字
    AUTO = auto()
    BREAK = auto()
    CASE = auto()
    CHAR = auto()
    CONST = auto()
    CONTINUE = auto()
    DEFAULT = auto()
    DO = auto()
    DOUBLE = auto()
    ELSE = auto()
    ENUM = auto()
    EXTERN = auto()
    FLOAT = auto()
    FOR = auto()
    GOTO = auto()
    IF = auto()
    INLINE = auto()
    INT = auto()
    LONG = auto()
    REGISTER = auto()
    RESTRICT = auto()
    RETURN = auto()
    SHORT = auto()
    SIGNED = auto()
    SIZEOF = auto()
    STATIC = auto()
    STRUCT = auto()
    SWITCH = auto()
    TYPEDEF = auto()
    UNION = auto()
    UNSIGNED = auto()
    VOID = auto()
    VOLATILE = auto()
    WHILE = auto()
    _BOOL = auto()
    _COMPLEX = auto()
    _IMAGINARY = auto()

    # 标识符和常量
    IDENTIFIER = auto()
    INTEGER_CONSTANT = auto()
    FLOATING_CONSTANT = auto()
    CHARACTER_CONSTANT = auto()
    STRING_LITERAL = auto()

    # 运算符和分隔符
    PLUS = auto()  # +
    MINUS = auto()  # -
    MULTIPLY = auto()  # *
    DIVIDE = auto()  # /
    MOD = auto()  # %
    INCREMENT = auto()  # ++
    DECREMENT = auto()  # --
    ASSIGN = auto()  # =
    ADD_ASSIGN = auto()  # +=
    SUB_ASSIGN = auto()  # -=
    MUL_ASSIGN = auto()  # *=
    DIV_ASSIGN = auto()  # /=
    MOD_ASSIGN = auto()  # %=
    AND = auto()  # &&
    OR = auto()  # ||
    NOT = auto()  # !
    BIT_AND = auto()  # &
    BIT_OR = auto()  # |
    BIT_XOR = auto()  # ^
    BIT_NOT = auto()  # ~
    LT = auto()  # <
    GT = auto()  # >
    LE = auto()  # <=
    GE = auto()  # >=
    EQ = auto()  # ==
    NE = auto()  # !=
    LEFT_SHIFT = auto()  # <<
    RIGHT_SHIFT = auto()  # >>
    LEFT_SHIFT_ASSIGN = auto()  # <<=
    RIGHT_SHIFT_ASSIGN = auto()  # >>=
    AND_ASSIGN = auto()  # &=
    OR_ASSIGN = auto()  # |=
    XOR_ASSIGN = auto()  # ^=
    DOT = auto()  # .
    ARROW = auto()  # ->
    QUESTION = auto()  # ?
    COLON = auto()  # :
    SEMICOLON = auto()  # ;
    COMMA = auto()  # ,
    LPAREN = auto()  # (
    RPAREN = auto()  # )
    LBRACKET = auto()  # [
    RBRACKET = auto()  # ]
    LBRACE = auto()  # {
    RBRACE = auto()  # }
    ELLIPSIS = auto()  # ...

    # 特殊令牌
    EOF = auto()
    INVALID = auto()
    PREPROCESSOR = auto() # #
    SINGLE_COMMENT = auto() # 单行注释
    MULTI_COMMENT = auto() # 多行注释

class Token:
    def __init__(self, startLine, endLine, startColumn, endColumn, startPos, endPos, tokenType, content, end=False):
        self.startLine = startLine
        self.endLine = endLine
        self.startColumn = startColumn
        self.endColumn = endColumn
        self.startPos = startPos
        self.endPos = endPos
        self.tokenType = tokenType
        self.content = content
        self.end = end

    def isEnd(self):
        return self.end

    def __str__(self):
        location = (f"行: {self.startLine}-{self.endLine}, "
                    f"列: {self.startColumn}-{self.endColumn}")
        type_name = self.tokenType
        content = f"内容: {repr(self.content)}" if self.content is not None else "无内容"
        return f"令牌信息: [{location}] 类型: {type_name} {content}"

class Lexer:
    # 关键字映射表
    _KEYWORDS = {
        "auto": TokenType.AUTO,
        "break": TokenType.BREAK,
        "case": TokenType.CASE,
        "char": TokenType.CHAR,
        "const": TokenType.CONST,
        "continue": TokenType.CONTINUE,
        "default": TokenType.DEFAULT,
        "do": TokenType.DO,
        "double": TokenType.DOUBLE,
        "else": TokenType.ELSE,
        "enum": TokenType.ENUM,
        "extern": TokenType.EXTERN,
        "float": TokenType.FLOAT,
        "for": TokenType.FOR,
        "goto": TokenType.GOTO,
        "if": TokenType.IF,
        "inline": TokenType.INLINE,
        "int": TokenType.INT,
        "long": TokenType.LONG,
        "register": TokenType.REGISTER,
        "restrict": TokenType.RESTRICT,
        "return": TokenType.RETURN,
        "short": TokenType.SHORT,
        "signed": TokenType.SIGNED,
        "sizeof": TokenType.SIZEOF,
        "static": TokenType.STATIC,
        "struct": TokenType.STRUCT,
        "switch": TokenType.SWITCH,
        "typedef": TokenType.TYPEDEF,
        "union": TokenType.UNION,
        "unsigned": TokenType.UNSIGNED,
        "void": TokenType.VOID,
        "volatile": TokenType.VOLATILE,
        "while": TokenType.WHILE,
        "_Bool": TokenType._BOOL,
        "_Complex": TokenType._COMPLEX,
        "_Imaginary": TokenType._IMAGINARY
    }

    # 操作符列表
    _OPERATORS = {
        "#": {
            "type": TokenType.PREPROCESSOR
        },
        "+": {
            "type": TokenType.PLUS,
            "+": {
                "type": TokenType.INCREMENT
            },
            "=": {
                "type": TokenType.ADD_ASSIGN
            }
        },
        "-": {
            "type": TokenType.MINUS,
            "-": {
                "type": TokenType.DECREMENT
            },
            "=": {
                "type": TokenType.SUB_ASSIGN
            },
            ">": {
                "type": TokenType.ARROW
            }
        },
        "*": {
            "type": TokenType.MULTIPLY,
            "=": {
                "type": TokenType.MUL_ASSIGN
            }
        },
        "/": {
            "type": TokenType.DIVIDE,
            "=": {
                "type": TokenType.DIV_ASSIGN
            }
        },
        "%": {
            "type": TokenType.MOD,
            "=": {
                "type": TokenType.MOD_ASSIGN
            }
        },
        "<": {
            "type": TokenType.LT,
            "<": {
                "type": TokenType.LEFT_SHIFT,
                "=": {
                    "type": TokenType.LEFT_SHIFT_ASSIGN
                }
            },
            "=": {
                "type": TokenType.LE
            }
        },
        ">": {
            "type": TokenType.GT,
            ">": {
                "type": TokenType.RIGHT_SHIFT,
                "=": {
                    "type": TokenType.RIGHT_SHIFT_ASSIGN
                }
            },
            "=": {
                "type": TokenType.GE
            }
        },
        "=": {
            "type": TokenType.ASSIGN,
            "=": {
                "type": TokenType.EQ
            }
        },
        "!": {
            "type": TokenType.NOT,
            "=": {
                "type": TokenType.NE
            }
        },
        "&": {
            "type": TokenType.BIT_AND,
            "&": {
                "type": TokenType.AND
            },
            "=": {
                "type": TokenType.AND_ASSIGN  # 修正原ADD_ASSIGN笔误
            }
        },
        "|": {
            "type": TokenType.BIT_OR,
            "|": {
                "type": TokenType.OR
            },
            "=": {
                "type": TokenType.OR_ASSIGN
            }
        },
        "^": {
            "type": TokenType.BIT_XOR,
            "=": {
                "type": TokenType.XOR_ASSIGN
            }
        },
        ".": {
            "type": TokenType.DOT,
            ".": {
                "type": None,  # 中间层占位（无单独类型）
                ".": {
                    "type": TokenType.ELLIPSIS
                }
            }
        },
        "~": {
            "type": TokenType.BIT_NOT
        },
        "?": {
            "type": TokenType.QUESTION
        },
        ":": {
            "type": TokenType.COLON
        },
        ";": {
            "type": TokenType.SEMICOLON
        },
        ",": {
            "type": TokenType.COMMA
        },
        "(": {
            "type": TokenType.LPAREN
        },
        ")": {
            "type": TokenType.RPAREN
        },
        "[": {
            "type": TokenType.LBRACKET
        },
        "]": {
            "type": TokenType.RBRACKET
        },
        "{": {
            "type": TokenType.LBRACE
        },
        "}": {
            "type": TokenType.RBRACE
        }
    }

    def __init__(self, content):
        self.content = content
        self.p = 0
        self.column = 0
        self.line = 0

    def memo(self):
        return {
            "column": self.column,
            "line": self.line,
            "p": self.p
        }

    def readMemo(self, data):
        self.column = data["column"]
        self.line = data["line"]
        self.p = data["p"]

    def peekChar(self, step=1):
        return self._peekChar(self.p, step)

    def _peekChar(self, p, step):
        if p >= len(self.content):
            return ""
        bCh = '' # 前一个字符
        ch = self.content[p]
        p1Ch = ''
        p2Ch = ''
        newP = p
        result = ch
        if p > 0:
            bCh = self.content[p-1]
        if p+1 < len(self.content):
            p1Ch = self.content[p+1]
        if p+2 < len(self.content):
            p2Ch = self.content[p+2]
        # 前一个字符不是转义字符
        if bCh != '\\':
            if ch=='\\' and p1Ch=='\n':
                newP += 3 # \ 换行 返回的char 返回的char的下一个(+3)
                result = p2Ch
            elif ch=="\\" and p1Ch=='\r':
                if p2Ch=='\n': # \ \r 换行 返回的char 返回的char的下一个(+4)
                    newP += 4
                    result = self.content[newP-1]
                else: # \ \r 返回的char 返回的char的下一个(+3)
                    newP += 3
                    result = p2Ch
            else:
                newP += 1
        else:
            newP += 1
        if step==0:
            return result
        else:
            return self._peekChar(newP, step-1)

    def getCharAndIncr(self):
        if self.p >= len(self.content):
            return ""
        bCh = '' # 前一个字符
        ch = self.content[self.p]
        p1Ch = ''
        p2Ch = ''
        if self.p > 0:
            bCh = self.content[self.p-1]
        if self.p+1 < len(self.content):
            p1Ch = self.content[self.p+1]
        if self.p+2 < len(self.content):
            p2Ch = self.content[self.p+2]
        # 前一个字符不是转义字符
        # print(self.p, 'bCh: ', bCh, 'ch: ', ch, 'p1Ch: ', p1Ch, hex(ord(p1Ch)))
        # print(ch=='\\' and p1Ch=='\n', ch=="\\" and p1Ch=='\r', p2Ch=='\n')
        if bCh != '\\':
            if ch=='\\' and p1Ch=='\n':
                self.p += 3 # \ 换行 返回的char 返回的char的下一个(+3)
                self.column = 0
                self.line += 1
                return p2Ch
            if ch=="\\" and p1Ch=='\r':
                if p2Ch=='\n': # \ \r 换行 返回的char 返回的char的下一个(+4)
                    self.p += 4
                    self.column = 0
                    self.line += 1
                    return self.content[self.p-1]
                else: # \ \r 返回的char 返回的char的下一个(+3)
                    self.p += 3
                    self.column = 0
                    self.line += 1
                    return p2Ch
        self.p += 1
        self.column += 1
        if ch=='\n':
            self.line += 1
            self.column = 0
        return ch

    def getIdentifier(self):
        token = Token(self.line, self.line, self.column, self.column, self.p, self.p, TokenType.IDENTIFIER, "")
        ch = self.content[self.p]
        while self.p < len(self.content) and (ch.isalpha() or ch.isdigit() or ch == '_'):
            token.content += ch
            ch = self.peekChar()
            self.getCharAndIncr()
        token.endLine = self.line
        token.endColumn = self.column-1
        token.endPos = self.p-1
        if token.content in self._KEYWORDS:
            token.tokenType = self._KEYWORDS[token.content]
        return token

    @staticmethod
    def _is_hex_digit(char: str) -> bool:
        return char.isdigit() or ('a' <= char.lower() <= 'f')

    def getDigit(self):
        # 记录数字起始位置（行、列）
        startLine = self.line
        startCol = self.column
        startP = self.p
        # 存储数字内容（含前缀、小数、指数、后缀）
        digitContent = ""
        # 标记数字类型相关状态
        isFloat = False
        isHex = False  # 是否十六进制
        hasExponent = False  # 是否有指数部分（e/E 或 p/P）
        base = 10  # 整数默认十进制
        currentChar = self.content[self.p]  # 当前字符（未消费）

        # 1. 处理进制前缀（0x/0X 或 0 开头的八进制）
        if currentChar == '0':
            digitContent += currentChar
            currentChar = self.peekChar()
            self.getCharAndIncr()  # 消费 '0'

            # 检查是否为十六进制（0x/0X）
            if currentChar.lower() == 'x':
                isHex = True
                base = 16
                digitContent += currentChar
                currentChar = self.peekChar()
                self.getCharAndIncr()  # 消费 'x' 或 'X'

                # 验证十六进制前缀后必须有数字（避免 "0x" 这种无效格式）
                if not self._is_hex_digit(currentChar):
                    digitContent += currentChar  # 保留无效字符便于报错
                    self.getCharAndIncr()
                    # 返回无效令牌（C99 不允许单独的 "0x"）
                    return Token(
                        startLine, self.line, startCol, self.column - 1, startP, self.p-1,
                        TokenType.INVALID, digitContent
                    )

            # 八进制（0 开头，后续为 0-7，若出现非八进制数字则转为无效）
            elif currentChar in '01234567' and not isHex:
                base = 8

        # 2. 处理数字主体（整数部分/小数部分/指数部分）
        if isHex:
            # 十六进制解析循环（仅处理十六进制合法字符）
            while currentChar != "":
                # 处理小数点
                if currentChar == '.':
                    isFloat = True
                    digitContent += currentChar
                    currentChar = self.peekChar()
                    self.getCharAndIncr()

                # 处理指数符p/P
                elif currentChar.lower() == 'p':
                    hasExponent = True
                    isFloat = True
                    digitContent += currentChar
                    currentChar = self.peekChar()
                    self.getCharAndIncr()

                    # 处理指数前的正负号
                    if currentChar in ('+', '-'):
                        digitContent += currentChar
                        currentChar = self.peekChar()
                        self.getCharAndIncr()

                # 普通十六进制字符（0-9, a-f, A-F）
                else:
                    digitContent += currentChar
                    currentChar = self.peekChar()
                    self.getCharAndIncr()

                # 循环终止条件：遇到非十六进制数字相关字符（因输入合法，实际会自然结束）
                if not (self._is_hex_digit(currentChar) or
                        (currentChar == '.' and not isFloat and not hasExponent) or
                        (currentChar.lower() == 'p' and not hasExponent) or
                        (currentChar in ('+', '-') and hasExponent)):
                    break

        else:
            # 十进制解析循环（仅处理十进制合法字符）
            while currentChar != "":
                # 处理小数点
                if currentChar == '.':
                    isFloat = True
                    digitContent += currentChar
                    currentChar = self.peekChar()
                    self.getCharAndIncr()

                # 处理指数符e/E
                elif currentChar.lower() == 'e':
                    hasExponent = True
                    isFloat = True
                    digitContent += currentChar
                    currentChar = self.peekChar()
                    self.getCharAndIncr()

                    # 处理指数前的正负号
                    if currentChar in ('+', '-'):
                        digitContent += currentChar
                        currentChar = self.peekChar()
                        self.getCharAndIncr()

                # 普通十进制数字（0-9）
                else:
                    digitContent += currentChar
                    currentChar = self.peekChar()
                    self.getCharAndIncr()

                # 循环终止条件：遇到非十进制数字相关字符（因输入合法，实际会自然结束）
                if not (currentChar.isdigit() or
                        (currentChar == '.' and not isFloat and not hasExponent) or
                        (currentChar.lower() == 'e' and not hasExponent) or
                        (currentChar in ('+', '-') and hasExponent)):
                    break

        # 3. 处理后缀（整数：u/U/l/L/ll/LL；浮点数：f/F/l/L）
        suffix = ""
        while currentChar != "" and currentChar.lower() in ('u', 'l', 'f'):
            # 整数后缀规则：u/U 与 l/L 可组合，l/L 最多 2 个，且不混合大小写
            if not isFloat:
                if currentChar in ('u', 'U'):
                    if 'u' in suffix.lower():
                        break  # 重复 u/U，停止解析
                elif currentChar in ('l', 'L'):
                    if suffix.count('l') + suffix.count('L') >= 2:
                        break  # l/L 超过 2 个，停止解析
                    if ('l' in suffix and currentChar == 'L') or ('L' in suffix and currentChar == 'l'):
                        break  # 混合 l/L，停止解析
            # 浮点数后缀规则：只能有一个 f/F/l/L，且不与整数后缀混用
            else:
                if suffix:
                    break  # 浮点数后缀最多 1 个
                if currentChar.lower() not in ('f', 'l'):
                    break  # 浮点数只能用 f/F/l/L

            suffix += currentChar
            digitContent += currentChar
            currentChar = self.peekChar()
            self.getCharAndIncr()

        # 4. 确定令牌类型（整数/浮点数）
        tokenType = TokenType.FLOATING_CONSTANT if isFloat else TokenType.INTEGER_CONSTANT

        # 5. 生成令牌（包含完整位置信息）
        return Token(
            startLine, self.line,
            startCol, self.column - 1,  # endCol 是最后一个字符的列号
            startP, self.p-1,
            tokenType,
            digitContent
        )

    def getString(self):
        token = Token(self.line, self.line, self.column, self.column, self.p, self.p,TokenType.STRING_LITERAL, '"')
        # 跳过 "
        b1Ch = self.content[self.p-2] if self.p-2 >= 0 else ""
        bCh = self.content[self.p-1] if self.p-1 >= 0 else ""
        ch = self.peekChar()
        self.getCharAndIncr()
        while self.p < len(self.content):
            # 当前字符串结束
            if ch=='"' and (bCh!='\\' or (bCh=='\\' and b1Ch=='\\')):
                # 跳过所有的 \ 换行和空字符
                self.getCharAndIncr()
                self.skipWhiteSpace()
                c = self.peekChar()
                # 如果还是 "
                if c=='"':
                    self.getCharAndIncr()
                    continue
                else:
                    token.content += '"'
                    break
            token.content += ch
            b1Ch = bCh
            bCh = ch
            ch = self.peekChar()
            self.getCharAndIncr()
        token.endColumn = self.column-1
        token.endPos = self.p-1
        token.endLine = self.line
        return token

    def getChar(self):
        token = Token(self.line, self.line, self.column, self.column, self.p, self.p, TokenType.CHAR, "'")
        self.getCharAndIncr()
        b2Ch = self.content[self.p-2] if self.p-2 >=0 else ''
        bCh = self.content[self.p-1] if self.p-1 >= 0 else ''
        ch = self.content[self.p]
        while self.p < len(self.content):
            token.content += ch
            if ch=="'" and (bCh!="\\" or (bCh=="\\" and b2Ch=="\\")):
                self.getCharAndIncr()
                break
            ch = self.peekChar()
            self.getCharAndIncr()
        token.endLine = self.line
        token.endColumn = self.column-1
        token.endPos = self.p-1
        return token

    def getOperator(self):
        token = Token(self.line, self.line, self.column, self.column, self.p, self.p, None, "")
        ch = self.content[self.p] if self.p < len(self.content) else ""
        p1Ch = self.peekChar() # 下一个字符
        p2Ch = self.peekChar(2) # 下两个字符
        self.getCharAndIncr()
        if ch in self._OPERATORS:
            if p1Ch in self._OPERATORS[ch]:
                self.getCharAndIncr()
                if p2Ch in self._OPERATORS[ch][p1Ch]:
                    self.getCharAndIncr()
                    if "type" in self._OPERATORS[ch][p1Ch][p2Ch]:
                        token.tokenType = self._OPERATORS[ch][p1Ch][p2Ch]["type"]
                    token.content = ch + p1Ch + p2Ch
                else:
                    if "type" in self._OPERATORS[ch][p1Ch]:
                        token.tokenType = self._OPERATORS[ch][p1Ch]["type"]
                    token.content = ch+p1Ch
            else:
                if "type" in self._OPERATORS[ch]:
                    token.tokenType = self._OPERATORS[ch]["type"]
                token.content = ch
        token.endLine = self.line
        token.endColumn = self.column-1
        token.endPos = self.p-1
        return token

    def getSingleComment(self):
        token = Token(self.line, self.line, self.column, self.column, self.p, self.p, TokenType.SINGLE_COMMENT, "//")
        self.getCharAndIncr()
        ch = self.peekChar()
        while self.p < len(self.content):
            if ch=='\n':
                self.getCharAndIncr()
                break
            token.content += ch
            self.getCharAndIncr()
            ch = self.peekChar()
        token.endColumn = self.column-1
        token.endPos = self.p - 1
        token.endLine = self.line
        return token

    def getMultiComment(self):
        token = Token(self.line, self.line, self.column, self.column, self.p, self.p, TokenType.MULTI_COMMENT, "/*")
        self.getCharAndIncr()
        bCh = ""
        ch = self.peekChar()
        while self.p < len(self.content):
            if ch=='/' and bCh=="*":
                token.content += '/'
                self.getCharAndIncr()
                self.getCharAndIncr()
                break
            token.content += ch
            self.getCharAndIncr()
            bCh = ch
            ch = self.peekChar()
        token.endColumn = self.column-1
        token.endPos = self.p-1
        token.endLine = self.line
        return token

    def getNextToken(self):
        if self.p >= len(self.content):
            return Token(0, 0, 0, 0, self.p, self.p, TokenType.EOF, "", True)
        while self.p < len(self.content):
            self.skipWhiteSpace()
            ch = self.content[self.p] if self.p < len(self.content) else ""
            if ch=='\\':
                self.p += 1
                continue
            # 解析标识符
            if ch.isalpha() or ch=='_':
                return self.getIdentifier()
            # 数字
            elif ch.isdigit() or ch==".":
                return self.getDigit()
            # 字符串
            elif ch=='"':
                return self.getString()
            # char
            elif ch=="'":
                return self.getChar()
            elif ch=='/' and self.peekChar()=='/':
                return self.getSingleComment()
            elif ch=='/' and self.peekChar()=='*':
                return self.getMultiComment()
            else:
                return self.getOperator()

    def peekToken(self, step=1):
        memoData = self.memo()
        token = self.getNextToken()
        step -= 1
        while step > 0:
            token = self.getNextToken()
            step -= 1
        self.readMemo(memoData)
        return token

    # 当前是否是换行符
    def isNewLine(self):
        return self.p>=len(self.content) or self.content[self.p]=='\n'

    def skipWhiteSpace(self):
        if self.p >= len(self.content):
            return
        ch = self.content[self.p]
        while ch.isspace() and self.p < len(self.content):
            if ch=='\n':
                self.line += 1
                self.column = 0
            elif ch=='\r':
                p1Ch = self.content[self.p+1] if self.p+1 < len(self.content) else ''
                if p1Ch=='\n':
                    self.p += 1
                self.line += 1
                self.column = 0
            else:
                self.column += 1
            self.p += 1
            ch = self.content[self.p] if self.p < len(self.content) else ""

if __name__ == '__main__':
    pass